package com.xj.demo.controller;

import com.xj.demo.entity.EsBlog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * <p> 响应式api测试 </p>
 *
 * @author xujj
 * @description
 * @date 2024/4/7 21:18
 */
@RestController()
@RequestMapping("/reactiveEs_template")
@Api(value = "响应式api——Template", tags = "响应式api——Template")
public class ReactiveEsBlog_templateController {


    private final ReactiveElasticsearchOperations reactiveElasticsearchTemplate;

    public ReactiveEsBlog_templateController(
            ReactiveElasticsearchOperations reactiveElasticsearchTemplate) {
        this.reactiveElasticsearchTemplate = reactiveElasticsearchTemplate;
    }


    @ApiOperation(value = "添加或更新更新文档", notes = "使用提供的数据添加或更新文档")
    @PutMapping("/saveAndUpdate")
    public Mono<EsBlog> updateDocument(@RequestBody EsBlog esBlog) {
        return reactiveElasticsearchTemplate.save(esBlog, IndexCoordinates.of("blog"));
    }

    @ApiOperation(value = "删除文档", notes = "根据唯一ID从Elasticsearch删除文档")
    @DeleteMapping("/delete/{id}")
    public Mono<String> deleteDocument(@PathVariable String id) {
        return reactiveElasticsearchTemplate.delete(id, EsBlog.class);
    }

    @ApiOperation(value = "根据ID获取文档", notes = "根据唯一ID从Elasticsearch检索文档")
    @GetMapping("/get/{id}")
    public Mono<EsBlog> getDocument(@PathVariable String id) {
        return reactiveElasticsearchTemplate.get(id, EsBlog.class);
    }

    @ApiOperation(value = "统计文档数量", notes = "检索Elasticsearch中所有文档的总数")
    @GetMapping("/count")
    public Mono<Long> countDocuments() {
        return reactiveElasticsearchTemplate.count(EsBlog.class);
    }

    @GetMapping(value = "/getAll", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "检索Elasticsearch中所有文档分页显示", notes = "检索Elasticsearch中所有文档分页显示")
    public Flux<EsBlog> getAllEntities(
            @RequestParam(name = "currentPage", required = false, defaultValue = "1") Integer currentPage,
            @RequestParam(name = "size", required = false, defaultValue = "10") Integer size) {
        return reactiveElasticsearchTemplate.search(
                new NativeSearchQueryBuilder()
                        .withQuery(QueryBuilders.matchAllQuery())
                        .withPageable(PageRequest.of(currentPage - 1, size))
                        .build(),
                EsBlog.class
        ).map(SearchHit::getContent);
    }

    @GetMapping("/searchByKeyWord")
    @ApiOperation(value = "根据条件检索Elasticsearch中文档", notes = "检索Elasticsearch中所有匹配关键字的文档，倒序分页且关键字高亮显示，返回指定字段")
    public Flux<EsBlog> searchEntities(
            @RequestParam(value = "keyWord") String keyWord,
            @RequestParam(name = "currentPage", required = false, defaultValue = "1") Integer currentPage,
            @RequestParam(name = "size", required = false, defaultValue = "10") Integer size) {

        HighlightBuilder highlightBuilder = new HighlightBuilder().field("content")// 指定需要高亮的字段名为 "content"
                .preTags("<em style='color:red'>") // 设置高亮文本前缀标签，这里使用红色显示
                .postTags("</em>") // 设置高亮文本后缀标签
                .fragmentSize(20) //每个高亮片段的最大长度为 20 个字符
                .numOfFragments(1); //每个文档最多只能有 1 个高亮片段
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                // 添加一个多字段匹配查询，查询关键字为 keyWord
                .withQuery(QueryBuilders.multiMatchQuery(keyWord, "title", "summary", "content"))
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC))// 设置排序，按照 "id" 字段降序排序
                .withHighlightBuilder(highlightBuilder) // 应用之前构建的高亮参数
                .withPageable(PageRequest.of(currentPage, size))// 设置分页参数，当前页和每页大小
                .withFields("id", "title", "summary", "content") // 设置返回的字段
                .build();
        return reactiveElasticsearchTemplate.search(searchQuery, EsBlog.class)
                .map(SearchHit::getContent);
    }
}
